package cn.zqy.demo2.day06.ThreadSafe;

/**
 卖票案例出现了线程安全问题
 卖出了不存在的票和重复的票

 解决线程安全问题的一种方案:【使用同步代码块】
 格式:
 synchronized(锁对象){
 可能会出现线程安全问题的代码(访问了共享数据的代码)
 }

 注意:
     1.通过代码块中的锁对象,可以使用任意的对象
     2.但是必须保证多个线程使用的锁对象是同一个
     3.锁对象作用:
        把同步代码块锁住,只让一个线程在同步代码块中执行
 * */
public class RunnableTicketSynchroMethodImpl implements Runnable{
    //定义一个多个线程共享的票源
    private int ticket = 100;
    private static int ticke = 100;


    //1. 创建一个锁方法【成员方法】
    public synchronized void Syncmethod01() {
        //先判断票是否存在
        if (ticket > 0) {
            try {
                //提高安全问题出现的概率,让程序睡眠
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ "正在卖第： " + ticket-- + "张票");
        }
    }

    //2. 创建一个锁方法【成员方法】
     /*
        定义一个同步方法
        同步方法也会把方法内部的代码锁住
        只让一个线程执行
        同步方法的锁对象是谁?
        就是实现类对象 new RunnableImpl()
        也是就是this
     */
    public void Syncmethod02() {
        synchronized (this) {
            //先判断票是否存在
            if (ticket > 0) {
                try {
                    //提高安全问题出现的概率,让程序睡眠
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+ "正在卖第： " + ticket-- + "张票");
            }
        }

    }


    @Override
    public void run() {
        while (true) {
            //同步方法
            Syncmethod04();
        }
    }


    /*
       静态的同步方法
       锁对象是谁?
       不能是this
       【this是创建对象之后产生的,静态方法优先于对象】
       静态方法的锁对象是本类的class属性-->class文件对象(反射)
    */
    // 3. 创建一个锁方法【静态方法】
    public static synchronized void Syncmethod03(){
        //先判断票是否存在
        if (ticke > 0) {
            try {
                //提高安全问题出现的概率,让程序睡眠
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+ "正在卖第： " + ticke-- + "张票");
        }
    }

    public static void Syncmethod04(){
        synchronized ( RunnableTicketSynchroMethodImpl.class) {
            //先判断票是否存在
            if (ticke > 0) {
                try {
                    //提高安全问题出现的概率,让程序睡眠
                    Thread.sleep(100);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+ "正在卖第： " + ticke-- + "张票");
            }
        }

    }
}
